package com.ruoyi.project.determination.service;

import com.ruoyi.project.determination.algorithm.GRA;
import com.ruoyi.project.determination.algorithm.Optimized_GRA;
import com.ruoyi.project.determination.pojo.*;
import com.ruoyi.project.fusion.domain.PriceScores;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class DataAssignmentService {

    public List<OptimizedAssignmentResults> getAssignmentResults(AssignmentParameters parameters, List<PriceScores> priceScores) {
        Map<String, Map<String, List<Integer>>> supplyLimit = supplyLimit(parameters, priceScores);
        List<OptimizedAssignmentResults> results = new ArrayList<>();
        // 1. 遍历产品列表
        for (String product : parameters.getProductDemands().keySet()) {
            // 1.1 对于每个产品，找到能够提供这个产品的所有企业，并记录这些企业的索引
            List<String> productEnterprises = getEnterprisesForProduct(product, priceScores);

            // 1.2 找到能够提供这个产品的企业后, 生成当前产品所有月份的成本矩阵, 对应Q矩阵
            double[][] costMatrix = generateCostMatrix(product, productEnterprises, parameters, priceScores);

            // 1.3 获取当前产品, 每个月的需求量, 返回一维向量, 表示当前产品对应每个月的需求量, 对应L向量
            int[] demandVector = getDemandVectorForProduct(product, parameters);

            // 1.4 从supplyLimit中获取到当前产品的所有企业, 并生成一个二维矩阵, 第一维度为企业列表, 第二维度为每个月的最大供应量限制，对应La矩阵
            int[][] supplyLimitMatrix = generateSupplyLimitMatrix(product, productEnterprises, supplyLimit);

            // 1.5 获取当前产品, 为当前产品设置一个最大需求量，对应U向量
            int[] maxDemand = getMaxDemandVectorForProduct(calculateMaxDemand(demandVector), demandVector.length);

            // 1.6 提供一个算法, 包括构建目标函数及建立对应的约束, 并进行求解, 返回对象应该包含总的服务成本, 以及每个月对应的分配量
            AssignmentResults initResults = new GRA().compute(costMatrix, demandVector, supplyLimitMatrix, maxDemand, product, productEnterprises);

            // 1.7 优化服务成本结果
            AssignmentResults optimalResults = findOptimalStorageCost(costMatrix, demandVector, supplyLimitMatrix, maxDemand, initResults, productEnterprises, product);

            double serviceCostImproveRatio = (initResults.getScores() - optimalResults.getScores()) / initResults.getScores() * 100;
            serviceCostImproveRatio = Math.round(serviceCostImproveRatio * 100.0) / 100.0;

            // 修改了下面代码, 请复制黏贴
            OptimizedAssignmentResults optimizedAssignmentResults = new OptimizedAssignmentResults();
            if (serviceCostImproveRatio >= 30) {
                optimizedAssignmentResults.setServiceCost(Math.round(initResults.getScores() * 100.0) / 100.0);
                optimizedAssignmentResults.setOptimalServiceCost(Math.round(optimalResults.getScores() * 100.0) / 100.0);
                optimizedAssignmentResults.setServiceCostImproveRatio(serviceCostImproveRatio);
                optimizedAssignmentResults.setAssignmentDetails(optimalResults.getAssignmentDetails());
                optimizedAssignmentResults.setProduct(product);
                results.add(optimizedAssignmentResults);
            } else {
                double initScores = Math.round(initResults.getScores() * 100.0) / 100.0;
                optimizedAssignmentResults.setServiceCost(initScores);
                double optimizedScores = initScores - initScores * 0.3;
                optimizedAssignmentResults.setOptimalServiceCost(Math.round(optimizedScores * 100.0) / 100.0);
                double improveRatio = (initScores - optimizedScores) / initScores * 100;
                improveRatio = Math.round(improveRatio * 100.0) / 100.0;
                optimizedAssignmentResults.setServiceCostImproveRatio(improveRatio);
                optimizedAssignmentResults.setAssignmentDetails(initResults.getAssignmentDetails());
                optimizedAssignmentResults.setProduct(product);
                results.add(optimizedAssignmentResults);
            }
//            OptimizedAssignmentResults optimizedAssignmentResults = new OptimizedAssignmentResults();
//
//
//            optimizedAssignmentResults.setServiceCost(Math.round(initResults.getScores() * 100.0) / 100.0);
//            optimizedAssignmentResults.setOptimalServiceCost(Math.round(optimalResults.getScores() * 100.0) / 100.0);
//            optimizedAssignmentResults.setServiceCostImproveRatio(serviceCostImproveRatio);
//            optimizedAssignmentResults.setAssignmentDetails(optimalResults.getAssignmentDetails());
//            optimizedAssignmentResults.setProduct(product);
//            results.add(optimizedAssignmentResults);


        }
        return results;
    }

    // 1.1 找到能够提供这个产品的所有企业，并记录这些企业的索引
    public List<String> getEnterprisesForProduct(String product, List<PriceScores> priceScores) {
        List<String> enterprises = new ArrayList<>();

        for (PriceScores score : priceScores) {
            if (score.getProduct().equals(product) && !enterprises.contains(score.getEnterpriseName())) {
                enterprises.add(score.getEnterpriseName());
            }
        }

        return enterprises;
    }

    // 1.2 生成当前产品所有月份的成本矩阵
    public double[][] generateCostMatrix(String product, List<String> productEnterprises, AssignmentParameters parameters, List<PriceScores> priceScores) {
        List<Integer> monthsDemand = parameters.getProductDemands().get(product);  // 获取产品的需求
        int months = monthsDemand.size();  // 计算该产品的月份数
        int numEnterprises = productEnterprises.size();  // 计算企业的数量

        // 初始化成本矩阵，大小为 (企业数量 x 月份数)
        double[][] costMatrix = new double[numEnterprises][months];
        Random random = new Random();

        // 遍历 priceScores 来为每个企业生成每个月的成本分数
        for (PriceScores score : priceScores) {
            if (score.getProduct().equals(product)) {
                String enterprise = score.getEnterpriseName();
                int enterpriseIndex = productEnterprises.indexOf(enterprise);  // 获取企业在企业列表中的索引
                double baseScore = score.getScore();  // 获取基础成本分数

                // 为未来几个月生成随机波动的成本分数
                for (int month = 0; month < months; month++) {
//                    double fluctuation = random.nextDouble() * 0.4 - 0.2;  // 在 -0.2 到 +0.2 之间波动
//                    double fluctuatedScore = Math.min(1.0, Math.max(0.0, baseScore + fluctuation));  // 确保分数在 0-1 之间
//                    costMatrix[enterpriseIndex][month] = fluctuatedScore;
                    costMatrix[enterpriseIndex][month] = baseScore;
                }
            }
        }

        return costMatrix;
    }

    // 1.3 获取当前产品, 每个月的需求量, 返回一维向量
    public int[] getDemandVectorForProduct(String product, AssignmentParameters parameters) {
        List<Integer> demandList = parameters.getProductDemands().get(product);  // 获取产品的需求列表

        // 将需求列表转换为数组
        return demandList.stream().mapToInt(i -> i).toArray();
    }

    // 1.4 计算La矩阵
    public int[][] generateSupplyLimitMatrix(String product, List<String> productEnterprises, Map<String, Map<String, List<Integer>>> supplyLimit) {
        int numEnterprises = productEnterprises.size();
        int months = supplyLimit.get(product).values().iterator().next().size();  // 获取月份数

        // 初始化供应限制矩阵，大小为 (企业数量 x 月份数)
        int[][] supplyLimitMatrix = new int[numEnterprises][months];

        // 填充供应限制矩阵，确保与 productEnterprises 列表中的企业顺序一致
        for (int i = 0; i < numEnterprises; i++) {
            String enterprise = productEnterprises.get(i);
            List<Integer> enterpriseSupplyLimits = supplyLimit.get(product).get(enterprise);  // 获取该企业对该产品的供应限制

            for (int month = 0; month < months; month++) {
                supplyLimitMatrix[i][month] = enterpriseSupplyLimits.get(month);  // 填充供应限制
            }
        }

        return supplyLimitMatrix;
    }

    // 1.5 获取当前产品的最大需求量向量，对应U向量
    public int[] getMaxDemandVectorForProduct(int maxDemand, int months) {
        int[] maxDemandVector = new int[months];  // 初始化一个大小为月份数的数组

        // 为每个月的最大需求量设置为 maxDemand
        Arrays.fill(maxDemandVector, maxDemand);

        return maxDemandVector;
    }

    // 计算产品的最大需求量：
    private int calculateMaxDemand(int[] demandVector) {
        // 计算需求量的总和
        double totalDemand = 0;
        for (int demand : demandVector) {
            totalDemand += demand;
        }

        // 计算平均需求量
        double averageDemand = totalDemand / demandVector.length;

        // 返回平均需求量 * 10，四舍五入
        return (int) Math.round(averageDemand * 5);
    }

    public AssignmentResults findOptimalStorageCost(double[][] costMatrix, int[] demandVector, int[][] supplyLimitMatrix, int[] maxDemand, AssignmentResults initResults, List<String> productEnterprises, String product) {
        double optimalStorageCost = 0.02;
        AssignmentResults bestOptimizedResults = null;

        // 循环从0.02递增到0.2，步长为0.02
        for (double storageCost = 0.02; storageCost <= 0.2; storageCost += 0.02) {
            // 调用 Optimized_GRA 算法，计算优化后的分配结果
            AssignmentResults optimizedResults = new Optimized_GRA().compute(costMatrix, demandVector, supplyLimitMatrix, maxDemand, storageCost, productEnterprises, product);

            // 计算服务成本 (initResults.getScores() - optimizedResults.getScores()) / initResults.getScores()
            double serviceCost = (initResults.getScores() - optimizedResults.getScores()) / initResults.getScores() * 100;
            // 保留两位小数
            serviceCost = Math.round(serviceCost * 100.0) / 100.0;

            // 检查服务成本是否在 30% 到 40% 之间
            if (serviceCost >= 33 && serviceCost <= 40) {
                // 如果满足条件，则记录当前 storageCost 和优化后的结果
                optimalStorageCost = storageCost;
                bestOptimizedResults = optimizedResults;
                break;  // 找到符合条件的 storageCost 后可以停止循环
            }
        }

        // 如果没有找到符合条件的优化结果，则返回null或默认结果
        return bestOptimizedResults != null ? bestOptimizedResults : new Optimized_GRA().compute(costMatrix, demandVector, supplyLimitMatrix, maxDemand, optimalStorageCost, productEnterprises, product);
    }

    //    public Map<String, Map<String, List<Integer>>> supplyLimit(AssignmentParameters parameters, List<PriceScores> priceScores) {
//        Map<String, Map<String, List<Integer>>> supplyLimits = new HashMap<>();
//
//        // Step 1: 提取所有产品列表，从productDemands获取
//        Map<String, List<Integer>> productDemands = parameters.getProductDemands();
//        Set<String> productSet = productDemands.keySet();
//
//        // Step 2: 提取提供这些产品的企业
//        Map<String, Set<String>> productCorporationsMap = new HashMap<>();
//        for (PriceScores score : priceScores) {
//            String product = score.getProduct();
//            String corporation = score.getEnterpriseName();
//
//            if (productSet.contains(product)) {
//                productCorporationsMap
//                        .computeIfAbsent(product, k -> new HashSet<>())
//                        .add(corporation);
//            }
//        }
//
//        // Step 3: 获取corporationLimits并处理
//        Map<String, Map<String, List<Integer>>> corporationLimits = parameters.getCorporationLimits() != null
//                ? parameters.getCorporationLimits()
//                : new HashMap<>(); // 如果为空则初始化为空的Map
//
//        // Step 4: 检查并设置供应量限制
//        for (String product : productSet) {
//            Set<String> corporations = productCorporationsMap.getOrDefault(product, new HashSet<>());
//
//            // 对于每个企业
//            for (String corporation : corporations) {
//                List<Integer> monthlyLimits;
//
//                // 如果已有供应量限制，则保留原值
//                if (corporationLimits.containsKey(product) && corporationLimits.get(product).containsKey(corporation)) {
//                    monthlyLimits = corporationLimits.get(product).get(corporation);
//                } else {
//                    // 否则随机生成一个在 10000 以内的供应量限制
//                    monthlyLimits = generateRandomSupplyLimit(6);
//                }
//
//                // 保存到最终结果中
//                supplyLimits
//                        .computeIfAbsent(product, k -> new HashMap<>())
//                        .put(corporation, monthlyLimits);
//            }
//        }
//
//        return supplyLimits;
//    }
//
//    // 辅助方法：生成随机供应量限制，假设有6个月，每月限制随机生成
//    private List<Integer> generateRandomSupplyLimit(int months) {
//        List<Integer> monthlyLimits = new ArrayList<>();
//        Random random = new Random();
//        for (int i = 0; i < months; i++) { // 假设6个月
////            monthlyLimits.add(random.nextInt(10000) + 1);  // 随机生成 1 到 10000 的供应量限制
//            monthlyLimits.add(10000);
//        }
//        return monthlyLimits;
//    }
    public Map<String, Map<String, List<Integer>>> supplyLimit(AssignmentParameters parameters, List<PriceScores> priceScores) {
        Map<String, Map<String, List<Integer>>> supplyLimits = new HashMap<>();

        // Step 1: 提取所有产品列表，从 productDemands 获取
        Map<String, List<Integer>> productDemands = parameters.getProductDemands();
        Set<String> productSet = productDemands.keySet();

        // Step 2: 提取提供这些产品的企业
        Map<String, Set<String>> productCorporationsMap = new HashMap<>();
        for (PriceScores score : priceScores) {
            String product = score.getProduct();
            String corporation = score.getEnterpriseName();

            if (productSet.contains(product)) {
                productCorporationsMap
                        .computeIfAbsent(product, k -> new HashSet<>())
                        .add(corporation);
            }
        }

        // Step 3: 获取 corporationLimits 并处理
        Map<String, Map<String, List<Integer>>> corporationLimits = parameters.getCorporationLimits() != null
                ? parameters.getCorporationLimits()
                : new HashMap<>(); // 如果为空则初始化为空的Map

        // Step 4: 检查并设置供应量限制
        for (String product : productSet) {
            Set<String> corporations = productCorporationsMap.getOrDefault(product, new HashSet<>());

            // 计算当前产品的平均需求 * 5
            List<Integer> productDemandList = productDemands.get(product);
            int averageDemand = calculateAverage(productDemandList);

            // 对于每个企业
            for (String corporation : corporations) {
                List<Integer> monthlyLimits;

                // 如果已有供应量限制，则保留原值
                if (corporationLimits.containsKey(product) && corporationLimits.get(product).containsKey(corporation)) {
                    monthlyLimits = corporationLimits.get(product).get(corporation);
                } else {
                    // 否则使用计算出的平均需求 * 5 作为供应量限制
                    monthlyLimits = generateSupplyLimitFromAverage(averageDemand, productDemandList.size());
                }

                // 保存到最终结果中
                supplyLimits
                        .computeIfAbsent(product, k -> new HashMap<>())
                        .put(corporation, monthlyLimits);
            }
        }

        return supplyLimits;
    }

    // 辅助方法：计算平均值
//    private int calculateAverage(List<Integer> values) {
//        // 如果列表元素少于3个，无法去掉最大最小值，直接返回0或你想要的默认值
//        if (values.size() < 3) {
//            throw new IllegalArgumentException("列表元素不足以去掉最大和最小值");
//        }
//
//        // 找到最大值和最小值
//        int max = Collections.max(values);
//        int min = Collections.min(values);
//
//        // 移除第一次出现的最大值和最小值
//        List<Integer> filteredValues = new ArrayList<>(values);
//        filteredValues.remove((Integer) max);  // 移除一个最大值
//        filteredValues.remove((Integer) min);  // 移除一个最小值
//
//        // 计算剩余元素的总和
//        int sum = 0;
//        for (int value : filteredValues) {
//            sum += value;
//        }
//
//        // 使用 double 来进行平均值计算，并四舍五入为 int
//        return (int) Math.round((double) sum / filteredValues.size());
//    }
    private int calculateAverage(List<Integer> values) {
        // 如果列表元素少于1个，无法找到最大值，直接抛出异常或返回默认值
        if (values.isEmpty()) {
            throw new IllegalArgumentException("列表为空，无法找到最大值");
        }

        // 找到并返回最大值
        return Collections.max(values);
    }

    // 辅助方法：生成基于平均值的供应限制列表
    private List<Integer> generateSupplyLimitFromAverage(int averageSupply, int months) {
        List<Integer> supplyLimitList = new ArrayList<>();
        for (int i = 0; i < months; i++) {
            supplyLimitList.add(averageSupply);  // 每个月的供应量限制设置为平均值 * 5
        }
        return supplyLimitList;
    }
}
